﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using ASBCC.Database.Entity;
using ASBCC.Database.Service;
using ASBCC.Workflow.Client;
using ASBCC.Workflow.K2Manager;

namespace BEGDC.CC.Web.Workflow
{
    public class WorkflowBasePage : BasePage, ASBCC.Workflow.Client.IWorkflowPage
    {
        #region Form Arguments

        private HiddenField _actionTypeArgument;

        protected HiddenField ActionTypeArgument
        {
            get
            {
                if (_actionTypeArgument == null)
                {
                    _actionTypeArgument = new HiddenField();
                    _actionTypeArgument.EnableViewState = false;
                    _actionTypeArgument.ID = "__wf_argument_actionType";
                }
                return _actionTypeArgument;
            }
        }

        private HiddenField _auditDestinationArgument;

        protected HiddenField AuditDestinationArgument
        {
            get
            {
                if (_auditDestinationArgument == null)
                {
                    _auditDestinationArgument = new HiddenField();
                    _auditDestinationArgument.EnableViewState = false;
                    _auditDestinationArgument.ID = "__wf_argument_auditDestination";
                }
                return _auditDestinationArgument;
            }
        }

        private HiddenField _auditDestinationAssignedArgument;

        protected HiddenField AuditDestinationAssignedArgument
        {
            get
            {
                if (_auditDestinationAssignedArgument == null)
                {
                    _auditDestinationAssignedArgument = new HiddenField();
                    _auditDestinationAssignedArgument.EnableViewState = false;
                    _auditDestinationAssignedArgument.ID = "__wf_argument_auditDestination_Assigned";
                }
                return _auditDestinationAssignedArgument;
            }
        }

        private bool _IsExcuteAction = true;

        public bool IsExcuteAction
        {
            get
            {
                return _IsExcuteAction;
            }
            set
            {
                _IsExcuteAction = value;
            }
        }

        private HiddenField _commentArgument;

        protected HiddenField CommentArgument
        {
            get
            {
                if (_commentArgument == null)
                {
                    _commentArgument = new HiddenField();
                    _commentArgument.EnableViewState = false;
                    _commentArgument.ID = "__wf_argument_comment";
                }
                return _commentArgument;
            }
        }

        #endregion

        #region Private Fields

        private Dictionary<string, object> _formArguments = new Dictionary<string, object>();
        protected MyActivityTableEntity _myActivity;
        protected bool _myActivityAssigned;
        private K2User _currentUser;

        #endregion

        #region Shared Members

        protected IWorkflowController _workflowController;

        protected int? NewAppFormId
        {
            get
            {
                object objNewAppFormId = ViewState["NewAppFormId"];
                if (objNewAppFormId == null)
                {
                    return null;
                }
                else
                {
                    return (int)ViewState["NewAppFormId"];
                }
            }
            set
            {
                if (value.HasValue)
                {
                    ViewState["NewAppFormId"] = value.Value;
                }
                else
                {
                    ViewState["NewAppFormId"] = null;
                }
            }
        }
        public int NewAppFormID
        {
            get
            {
                object objNewAppFormId = ViewState["NewAppFormId"];
                if (objNewAppFormId == null)
                {
                    return 0;
                }
                else
                {
                    return (int)ViewState["NewAppFormId"];
                }
            }
        }

        protected string GetNewFolio()
        {
            return Guid.NewGuid().ToString();
        }

        protected int? GetAppFormId()
        {
            int appFormId;
            string id = Request.QueryString[GetRequestParamKey_AppFormId()];
            bool res = int.TryParse(id, out appFormId);
            if (res)
            {
                return appFormId;
            }
            else
            {
                return NewAppFormId;
            }
        }

        protected Guid? GetMyActivityId()
        {
            string id = Request.QueryString[GetRequestParamKey_MyActivityId()];
            if (string.IsNullOrEmpty(id)) return null;
            try
            {
                return new Guid(id);
            }
            catch (Exception)
            {
                return null;
            }
        }

        protected K2User GetCurrentUser()
        {
            if (_currentUser == null)
            {
                _currentUser = new K2User(UserInfo.EmployeeID.Value, UserInfo.NameCN, UserInfo.NameChinese);
            }
            return _currentUser;
        }

        protected IWorkflowControl _processStampControl;

        /// <summary>
        /// 当前用户有待办的情况下，取得流程当前节点名称
        /// </summary>
        /// <returns></returns>
        protected string GetCurrentActivityName()
        {
            MyActivityTableEntity myActivity = GetMyActivity();
            if (myActivity == null) return string.Empty;
            return myActivity.K2ActivityName;
        }

        /// <summary>
        /// 当前用户有待办的情况下，取得流程的目标节点。
        /// 流程处于AskedForMore状态，可通过这个方法获取目标节点，即哪个节点被AskForMore。
        /// 在其他情况下GetCurrentTargetActivityName返回的值跟GetCurrentActivityName返回的值相同
        /// </summary>
        /// <returns></returns>
        protected string GetCurrentTargetActivityName()
        {
            MyActivityTableEntity myActivity = GetMyActivity();
            if (myActivity == null) return string.Empty;
            return myActivity.TargetActivityName;
        }

        protected string GetDestinationActivityName()
        {
            Dictionary<string, object> formArguments = GetFormArguments();
            object objAuditDestination = formArguments[WorkflowKeyConsts.AuditDestination];
            if (objAuditDestination == null) return string.Empty;
            string strAuditDestination = objAuditDestination.ToString();
            if (string.IsNullOrEmpty(strAuditDestination)) return string.Empty;

            K2AuditDestination auditDestination = K2AuditDestination.LoadText(strAuditDestination);
            if (auditDestination == null || auditDestination.ActivityDestinationList.Count == 0) return string.Empty;
            K2AuditDestination.ActivityDestination activityDestination = auditDestination.ActivityDestinationList[0];
            if (activityDestination == null) return string.Empty;
            return activityDestination.ActivityName;
        }

        protected int[] GetDestinationUsers()
        {
            Dictionary<string, object> formArguments = GetFormArguments();
            object objAuditDestination = formArguments[WorkflowKeyConsts.AuditDestination];
            if (objAuditDestination == null) return null;
            string strAuditDestination = objAuditDestination.ToString();
            if (string.IsNullOrEmpty(strAuditDestination)) return null;

            K2AuditDestination auditDestination = K2AuditDestination.LoadText(strAuditDestination);
            if (auditDestination == null || auditDestination.ActivityDestinationList.Count == 0) return null;
            K2AuditDestination.ActivityDestination activityDestination = auditDestination.ActivityDestinationList[0];
            if (activityDestination == null) return null;
            return activityDestination.UserArr;
        }

        #endregion

        #region Inner Helper

        protected string GetReloadUrl()
        {
            Dictionary<string, object> formArguments = GetFormArguments();
            string formUrl = formArguments[WorkflowKeyConsts.FormUrl].ToString();
            string appFormId_Key = GetRequestParamKey_AppFormId();
            string myActivityId_Key = GetRequestParamKey_MyActivityId();
            string rootUrl;
            Dictionary<string, string> queryStringParameters;
            WorkflowUtility.ParseUrl(formUrl, out rootUrl, out queryStringParameters);

            string foundAppFormId_Key = WorkflowUtility.FindKeyInDictionary(queryStringParameters, appFormId_Key, true);
            string foundMyActivityId_Key = WorkflowUtility.FindKeyInDictionary(queryStringParameters, myActivityId_Key, true);
            string foundRandom_Key = WorkflowUtility.FindKeyInDictionary(queryStringParameters, AppFormUrlKeyConsts.Random, true);
            if (string.IsNullOrEmpty(foundAppFormId_Key))
            {
                int appFormId = GetAppForm().AppFormId;
                queryStringParameters.Add(appFormId_Key, appFormId.ToString());
            }
            if (!string.IsNullOrEmpty(foundMyActivityId_Key))
            {
                queryStringParameters.Remove(foundMyActivityId_Key);
            }
            if (!string.IsNullOrEmpty(foundRandom_Key))
            {
                queryStringParameters.Remove(foundRandom_Key);
            }
            queryStringParameters.Add(AppFormUrlKeyConsts.Random, new Random().Next(int.MaxValue).ToString());

            return WorkflowUtility.CombineUrl(rootUrl, queryStringParameters);
        }

        private void InitProcessStampControl()
        {
            System.Web.UI.Control control = (System.Web.UI.Control)GetProcessStampControl();
            if (control == null) return;
            System.Web.UI.HtmlControls.HtmlGenericControl br = new System.Web.UI.HtmlControls.HtmlGenericControl("br");
            System.Web.UI.HtmlControls.HtmlGenericControl div = new System.Web.UI.HtmlControls.HtmlGenericControl("div");
            div.Controls.Add(control);
            this.GetPlaceHolder().Controls.Add(br);
            this.GetPlaceHolder().Controls.Add(div);
        }

        private void BindProcessStampControl()
        {
            IWorkflowControl processStampControl = GetProcessStampControl();
            if (processStampControl != null)
            {
                IAppForm appForm = GetAppForm();
                processStampControl.BindData(appForm.AppFormId, appForm.ProcInstId);
            }
        }

        private void RegisterWorkflowScripts()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("function __wf_getActionTypeArgumentControl() {0} return document.getElementById('{2}'); {1} ", "{", "}", ActionTypeArgument.ClientID).AppendLine();
            sb.AppendFormat("function __wf_getAuditDestinationArgumentControl() {0} return document.getElementById('{2}'); {1} ", "{", "}", AuditDestinationArgument.ClientID).AppendLine();
            sb.AppendFormat("function __wf_getAuditDestinationAssignedArgumentControl() {0} return document.getElementById('{2}'); {1} ", "{", "}", AuditDestinationAssignedArgument.ClientID).AppendLine();
            sb.AppendFormat("function __wf_getCommentArgumentControl() {0} return document.getElementById('{2}'); {1} ", "{", "}", CommentArgument.ClientID).AppendLine();

            if (!ClientScript.IsClientScriptBlockRegistered("WorkflowScript"))
            {
                ClientScript.RegisterClientScriptBlock(this.GetType(), "WorkflowScript", sb.ToString(), true);
            }
        }

        #endregion

        #region Overrided Members

        protected override void OnInit(EventArgs e)
        {
            if (GetAppForm() == null)
            {
                base.OnInit(e);
                return;
            }
            GetPlaceHolder().Controls.Add(ActionTypeArgument);
            GetPlaceHolder().Controls.Add(AuditDestinationArgument);
            GetPlaceHolder().Controls.Add(AuditDestinationAssignedArgument);
            GetPlaceHolder().Controls.Add(CommentArgument);
            InitProcessStampControl();
            base.OnInit(e);
            RegisterWorkflowController();
            RegisterWorkflowScripts();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            OnPreWorkflowLoadDone(e);
            OnWorkflowLoadDone(e);
        }

        #endregion

        #region Virtual Members

        /// <summary>
        /// 注册WorkflowController
        /// 如果DefaultWorkflowController不符合要求，需要实现自定义的WorkflowController并重载此方法注册
        /// </summary>
        public virtual void RegisterWorkflowController()
        {
            _workflowController = new DefaultWorkflowController(this, GetAppForm(), GetMyActivity());
        }

        /// <summary>
        /// 获取页面中PlaceHolder控件的实例
        /// ProcessStamp用户控件将被放到这个PlaceHolder控件中
        /// </summary>
        /// <returns></returns>
        public virtual PlaceHolder GetPlaceHolder()
        {
            return null;
        }

        /// <summary>
        /// 构建FormArguments
        /// 如果流程有特殊要求需要特定的FormAregument，需要重载这个函数增加需要的参数
        /// 这个函数需要在Control Event之前调用；在Page和UserControl的OnLoad之后调用
        /// 由于UserControl的OnLoad发生在Page的OnLoad之后，所以如果FormArgument的来源
        /// 在UserControl的OnLoad中初始化，那么在Page的OnLoadDone中调用BuildFormArguments将
        /// 来不及获取这些值，在这种情况下需要做特殊处理，单独调用BuildFormArguments
        /// </summary>
        public virtual void BuildFormArguments()
        {
            Dictionary<string, object> formArguments = GetFormArguments();
            formArguments[WorkflowKeyConsts.ActionType] = ActionTypeArgument.Value;
            formArguments[WorkflowKeyConsts.AskformoreProcInstID] = null;

            if (AuditDestinationArgument.Value.Contains("askformore:"))
            {
                AuditDestinationArgument.Value = BuidAskForMoreAuditDestination(AuditDestinationArgument.Value);
            }
            formArguments[WorkflowKeyConsts.AuditDestination] = AuditDestinationArgument.Value;
            formArguments[WorkflowKeyConsts.AuditDestinationAssgined] = AuditDestinationAssignedArgument.Value;
            formArguments[WorkflowKeyConsts.Comment] = CommentArgument.Value;
            formArguments[WorkflowKeyConsts.CurrentUserId] = base.UserInfo.EmployeeID;
            formArguments[WorkflowKeyConsts.CurrentUserEn] = base.UserInfo.NameCN;
            formArguments[WorkflowKeyConsts.CurrentUserCn] = base.UserInfo.NameChinese;

            MyActivityTableEntity myActivity = GetMyActivity();
            if (myActivity != null)
            {
                formArguments[WorkflowKeyConsts.DelegateFromId] = myActivity.DelegateFromID ?? 0;
                formArguments[WorkflowKeyConsts.DelegateFromEn] = myActivity.DelegateFromEn;
                formArguments[WorkflowKeyConsts.DelegateFromCn] = myActivity.DelegateFromCn;
            }

            formArguments[WorkflowKeyConsts.FormUrl] = Request.Url.AbsoluteUri;
        }

        public virtual void InitActionPanel()
        {
            GetWorkflowController().InitActionPanel();
        }

        private string BuidAskForMoreAuditDestination(string askformoreAction)
        {
            Dictionary<string, object> formArguments = GetFormArguments();
            askformoreAction = askformoreAction.Replace("askformore:", "");
            string[] askformoreInfos = askformoreAction.Split('|');
            if (askformoreInfos.Length >= 2)
            {
                string actionName = askformoreInfos[0];
                int askformoreProcInstId = int.Parse(askformoreInfos[1]);
                formArguments[WorkflowKeyConsts.AskformoreProcInstID] = askformoreProcInstId;
                if (askformoreInfos.Length == 2 || (askformoreInfos.Length == 3 && string.IsNullOrEmpty(askformoreInfos[2])))
                {
                    Flow_ActionRecordTableEntitySet set = Flow_ActionRecordManager.SelectByCondition(string.Format(" ProcInstID={0} and ActivityName='{1}' order by ActionDate", askformoreProcInstId, actionName));
                    if (set.Count > 0)
                    {
                        return actionName + "|" + set[0].OwnerID.ToString();
                    }
                    else
                    {
                        throw new Exception(" ask for audituser cann't find!");
                    }
                }
                else
                {
                    if (askformoreInfos.Length == 4)
                    {
                        return actionName + "|" + askformoreInfos[2] + "|" + askformoreInfos[3];
                    }
                    else
                    {
                        return actionName + "|" + askformoreInfos[2];
                    }
                }
            }
            throw new Exception(" ask for more fomat error!");
        }

        /// <summary>
        /// 如果重载页面需要在Base.OnLoad之后做一些动作，需要重载此方法，而不是重载OnLoad方法
        /// </summary>
        /// <param name="e"></param>
        public virtual void OnPreWorkflowLoadDone(EventArgs e)
        {
        }

        /// <summary>
        /// 如果不需要在Page的OnLoad中调用BuildFormArguments，可以重载该函数使该函数不做任何动作
        /// </summary>
        /// <param name="e"></param>
        public virtual void OnWorkflowLoadDone(EventArgs e)
        {
            if (GetAppForm() == null)
            {
                return;
            }

            BuildFormArguments();
            InitActionPanel();
            BindProcessStampControl();
        }

        #endregion

        #region IWorkflowPage Members

        /// <summary>
        /// 指定页面跟哪个流程关联
        /// </summary>
        /// <returns></returns>
        public virtual string GetProcName()
        {
            return null;
        }

        /// <summary>
        /// 获取AppForm对象
        /// 该方法会被Page.OnInit方法调用，AppForm对象在这时被创建
        /// </summary>
        /// <returns></returns>
        public virtual IAppForm GetAppForm()
        {
            return null;
        }

        public virtual bool IsViewOnly()
        {
            return Request.QueryString["ViewOnly"] == "1";
        }

        public virtual string GetRequestParamKey_AppFormId()
        {
            return "ID";
        }

        public virtual string GetRequestParamKey_MyActivityId()
        {
            return "MyActID";
        }

        public virtual MyActivityTableEntity GetMyActivity()
        {
            if (!_myActivityAssigned)
            {
                Guid? myActivityId = GetMyActivityId();
                MyActivityTableEntity myActivity = null;
                if (myActivityId.HasValue)
                {
                    MyActivityTableEntity myAct = MyActivityManager.SelectByKeys(myActivityId.Value);
                    if (myAct != null && myAct.Status == (int)MyActivityStatus.Normal)
                    {
                        myActivity = myAct;
                    }
                }
                if (myActivity == null)
                {
                    IAppForm appForm = GetAppForm();
                    bool isDraft = string.IsNullOrEmpty(appForm.ProcessStatus) || appForm.ProcessStatus == ProcessStatusConsts.Draft;
                    if (!isDraft && appForm.ProcInstId > 0)
                    {
                        K2User currentUser = GetCurrentUser();
                        myActivity = K2DataHelper.GetOneOfMyActivities(appForm.ProcInstId, currentUser.UserId, new int[] { (int)MyActivityStatus.Normal });
                    }
                }
                _myActivity = myActivity;
                _myActivityAssigned = true;
            }
            return _myActivity;
        }

        public IWorkflowController GetWorkflowController()
        {
            return _workflowController;
        }

        public virtual IWorkflowActionPanel GetActionPanel()
        {
            return null;
        }

        public virtual IWorkflowControl GetProcessStampControl()
        {
            if (this._processStampControl == null)
            {
                System.Web.UI.Control control = this.LoadControl("~/Workflow/ProcessStamp/EZVisitProcessStampControl.ascx");
                this._processStampControl = (IWorkflowControl)control;
            }
            return this._processStampControl;
        }

        public Dictionary<string, object> GetFormArguments()
        {
            return _formArguments;
        }

        public virtual bool ExecuteAction(string actionType)
        {
            return true;
        }

        public virtual void ExecuteActionDone(string actionType)
        {
            Button actionButton = this.GetActionPanel().GetActionButton(actionType);

            if (actionButton == null)
            {
                return;
            }

            string script = string.Format(" window.showModalDialog('../Workflow/Dialog/WorkflowDialog.aspx?info={0}&rdm={1}&ProcessName={2}', window, 'dialogHeight:280px;dialogWidth:380px;center:yes;resizable:no;status:no;scroll:no'); ",
                     "",
                    new Random().Next(int.MaxValue),
                    HttpUtility.UrlEncode(this.GetProcName())
                    );

            ScriptManager.RegisterClientScriptBlock(actionButton, actionButton.GetType(), "OperationResult", script, true);

            script = this.GetCloseClientScript();

            ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "Reload", script, true);
        }

        public string GetCloseClientScript()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("try { ");
            sb.Append("  if (window.opener && !window.opener.closed && window.opener.location.href.toLowerCase().indexOf('MyActivities.aspx') > 0) { ");
            sb.Append("    window.opener.Approval_StatusChange(); ");
            sb.Append("  } else if (window.opener && !window.opener.closed && window.opener.RefreshGrid) { ");
            sb.Append("    window.opener.RefreshGrid(); ");
            sb.Append("	 } ");
            sb.Append("} ");
            sb.Append("catch (ex) { ");
            sb.Append("	");
            sb.Append("} ");
            // sb.Append("window.close(); ");
            sb.AppendFormat("document.location=\"{0}\";", GetReloadUrl());
            return sb.ToString();
        }

        #endregion
    }

    /// <summary>
    /// 工作流表单上的按钮类
    /// </summary>
    public class WorkflowButton
    {
        private Button button;
        private string actionType;
        private string name;

        public Button Button { get { return this.button; } }

        public string ActionType { get { return this.actionType; } }

        public string Name { get { return this.name; } }

        public WorkflowButton(Button button, string actionType, string name)
        {
            this.button = button;
            this.actionType = actionType;
            this.name = name;
        }
    }
}